/*-------------------------------------------------------------------------
 * drawElements Quality Program Tester Core
 * ----------------------------------------
 *
 * Copyright (c) 2014 The Android Open Source Project
 * Copyright (c) 2016 The Khronos Group Inc.
 * Copyright (c) 2016 Mun Gwan-gyeong <elongbug@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief wayland Egl Display Factory.
 *//*--------------------------------------------------------------------*/

#include "tcuLnxWaylandEglDisplayFactory.hpp"
#include "tcuLnxWayland.hpp"
#include "egluGLContextFactory.hpp"
#include "eglwLibrary.hpp"
#include "eglwFunctions.hpp"
#include "eglwEnums.hpp"
#include "deUniquePtr.hpp"

namespace tcu
{
namespace lnx
{
namespace wayland
{
namespace egl
{

using std::string;

using de::MovePtr;
using de::UniquePtr;
using glu::ContextFactory;
using eglu::GLContextFactory;
using eglu::NativeDisplay;
using eglu::NativeDisplayFactory;
using eglu::NativeWindow;
using eglu::NativeWindowFactory;
using eglu::NativePixmap;
using eglu::NativePixmapFactory;
using eglu::WindowParams;
using tcu::TextureLevel;

class Display : public NativeDisplay
{
public:
	static const Capability CAPABILITIES		= Capability(CAPABILITY_GET_DISPLAY_LEGACY|
															 CAPABILITY_GET_DISPLAY_PLATFORM_EXT);

								Display				(MovePtr<wayland::Display> waylandDisplay)
									: NativeDisplay	(CAPABILITIES,
													 EGL_PLATFORM_WAYLAND_KHR,
													 "EGL_KHR_platform_wayland")
									, m_display		(waylandDisplay)
									, m_library		("libEGL.so") {}

	~Display(void) {}
	wayland::Display&			getWaylandDisplay	(void)	{ return *m_display; }
	eglw::EGLNativeDisplayType	getLegacyNative		(void)	{ return reinterpret_cast<eglw::EGLNativeDisplayType>(m_display->getDisplay()); }
	void*						getPlatformNative	(void)	{ return m_display->getDisplay(); }
	const eglw::Library&		getLibrary			(void) const	{ return m_library; }
	const eglw::EGLAttrib*		getPlatformAttributes	(void) const	{ return DE_NULL; }

private:
	UniquePtr<wayland::Display>		m_display;
	eglw::DefaultLibrary			m_library;
};

class Window : public NativeWindow
{
public:
	static const Capability	CAPABILITIES		= Capability(CAPABILITY_CREATE_SURFACE_LEGACY |
															 CAPABILITY_GET_SURFACE_SIZE |
															 CAPABILITY_SET_SURFACE_SIZE |
															 CAPABILITY_GET_SCREEN_SIZE);

								Window				(Display&				display,
													 const WindowParams&	params);

	eglw::EGLNativeWindowType	getLegacyNative		(void) { return reinterpret_cast<eglw::EGLNativeWindowType>(m_window.getWindow()); }
	IVec2						getSurfaceSize		(void) const;
	void						setSurfaceSize		(IVec2 size);
	IVec2						getScreenSize		(void) const { return getSurfaceSize(); }

private:
	wayland::Window				m_window;
};

Window::Window (Display& display, const WindowParams& params)
	: NativeWindow	(CAPABILITIES)
	, m_window		(display.getWaylandDisplay(), params.width, params.height)
{
}

IVec2 Window::getSurfaceSize (void) const
{
	IVec2 ret;
	m_window.getDimensions(&ret.x(), &ret.y());
	return ret;
}

void Window::setSurfaceSize (IVec2 size)
{
	m_window.setDimensions(size.x(), size.y());
}

class WindowFactory : public NativeWindowFactory
{
public:
						WindowFactory		(void);

	NativeWindow*		createWindow		(NativeDisplay*			nativeDisplay,
											 const WindowParams&	params) const;

	NativeWindow*		createWindow		(NativeDisplay*			nativeDisplay,
											 eglw::EGLDisplay		display,
											 eglw::EGLConfig		config,
											 const eglw::EGLAttrib*	attribList,
											 const WindowParams&	params) const;
};

WindowFactory::WindowFactory (void)
	: NativeWindowFactory ("window", "Wayland Window", Window::CAPABILITIES)
{
}

NativeWindow* WindowFactory::createWindow (NativeDisplay*		nativeDisplay,
										   const WindowParams&	params) const
{
	Display&	display	= *dynamic_cast<Display*>(nativeDisplay);

	return new Window(display, params);
}

NativeWindow* WindowFactory::createWindow (NativeDisplay*			nativeDisplay,
										   eglw::EGLDisplay			eglDisplay,
										   eglw::EGLConfig			config,
										   const eglw::EGLAttrib*	attribList,
										   const WindowParams&		params) const
{
	DE_UNREF(eglDisplay);
	DE_UNREF(config);
	DE_UNREF(attribList);

	Display&	display = *dynamic_cast<Display*>(nativeDisplay);

	return new Window(display, params);
}

class DisplayFactory : public NativeDisplayFactory
{
public:
						DisplayFactory		(EventState& eventState);

	NativeDisplay*		createDisplay		(const eglw::EGLAttrib* attribList) const;

private:
	EventState&			m_eventState;
};

DisplayFactory::DisplayFactory (EventState& eventState)
	: NativeDisplayFactory	("Wayland", "Native Wayland Display",
							 Display::CAPABILITIES,
							 EGL_PLATFORM_WAYLAND_KHR,
							 "EGL_KHR_platform_wayland")
	, m_eventState			(eventState)
{
	m_nativeWindowRegistry.registerFactory(new WindowFactory());
}

NativeDisplay* DisplayFactory::createDisplay (const eglw::EGLAttrib* attribList) const
{
	DE_UNREF(attribList);

	MovePtr<wayland::Display>	waylandDisplay	(new wayland::Display(m_eventState, DE_NULL));

	return new Display(waylandDisplay);
}

NativeDisplayFactory* createDisplayFactory (EventState& eventState)
{
	return new DisplayFactory(eventState);
}

} // egl
} // wayland
} // lnx
} // tcu
